import type { RouteRecordRaw } from "vue-router";
import type { RouteRecord } from "@/api/auth/types";
import { defineStore } from "pinia";
import { constantRoutes } from "@/router";
import { store } from "@/stores";
import { listRoutes } from "@/api/auth/index";
import type { RolesPerms } from "@/api/auth/types";

import { menus, dynamicRoutes, pathToPascalCase, defineComponentWithName } from "@/settings";

//组件计数
let componentCount = 1;

/**
 * 递归过滤有权限的异步(动态)路由
 *
 * @param routes 接口返回的异步(动态)路由
 * @returns 返回用户有权限的异步(动态)路由
 */
const filterAsyncRoutes = (routes: RouteRecord[]) => {
  const asyncRoutes: RouteRecordRaw[] = [];

  routes.forEach((route) => {
    const tmpRoute: RouteRecordRaw = {
      path: route.path,
      name: route.name,
      meta: route.meta,
      children: []
    };
    if (route.redirect != undefined) {
      tmpRoute.redirect = route.redirect;
    }

    // 判断本地是否注册路由组件.
    const component = menus.get(route.componentName);
    if (component) {
      const newComponentName = pathToPascalCase(route.componentName as string) + componentCount++;
      if (route.componentName === "Layout") {
        tmpRoute.component = component;
      } else {
        const customComp = async () => {
          const newComponent = await component();
          return defineComponentWithName(newComponent.default, newComponentName);
        };
        tmpRoute.component = customComp;
      }
      tmpRoute.name = newComponentName;
    }

    if (!tmpRoute.name) {
      tmpRoute.name = pathToPascalCase(route.path) + componentCount++;
    }

    //包含孩子组件,添加目录.
    if (route.children) {
      tmpRoute.children = filterAsyncRoutes(route.children);
    }

    //组件已注册 或 目录.
    if ((tmpRoute.component && route.componentName !== "Layout") || tmpRoute.children.length > 0) {
      asyncRoutes.push(tmpRoute);
    }
  });
  return asyncRoutes;
};
/** 过滤动态路由. */
const filterDynamicRoutes = (rolesPerms: RolesPerms, routes: RouteRecordRaw[]) => {
  const asyncRoutes: RouteRecordRaw[] = [];

  routes.forEach((oldRoute) => {
    const route: RouteRecordRaw = { ...oldRoute };
    route.meta = { ...oldRoute.meta };
    //包含孩子组件,添加目录.
    if (oldRoute.children) {
      route.children = filterDynamicRoutes(rolesPerms, oldRoute.children);
    }
    if (route.meta && route.meta.roleCode) {
      if (
        rolesPerms.roleCodes.length > 0 &&
        rolesPerms.roleCodes.includes(route.meta.roleCode as string)
      ) {
        asyncRoutes.push(route);
      } else {
        console.log("403", route.path + "要求角色：" + route.meta.roleCode);
      }
    } else if (route.meta && route.meta.permCode) {
      if (
        rolesPerms.permCodes.length > 0 &&
        (rolesPerms.permCodes.includes("*") ||
          rolesPerms.permCodes.includes(route.meta.permCode as string))
      ) {
        asyncRoutes.push(route);
      } else {
        console.log("403", route.path + "要求权限：" + route.meta.permCode);
      }
    } else {
      asyncRoutes.push(route);
    }
  });
  return asyncRoutes;
};

// setup
export const usePermissionStore: any = defineStore("permission", () => {
  // state
  const routes = ref<RouteRecordRaw[]>([]);

  // actions
  function setRoutes(newRoutes: RouteRecordRaw[]) {
    routes.value = constantRoutes.concat(newRoutes);
  }
  /**
   * 生成动态路由
   *
   * @param roles 用户角色集合
   * @returns
   */
  function generateRoutes(rolesPerms: RolesPerms) {
    return new Promise<RouteRecordRaw[]>((resolve, reject) => {
      // 接口获取所有路由
      listRoutes()
        .then(({ data }) => {
          //console.log("Server Menus...", data);
          // 根据角色获取有访问权限的路由
          const accessedRoutes = filterAsyncRoutes(data.menus);
          // 根据角色和权限过滤动态路由
          const accessedRoutes2 = filterDynamicRoutes(rolesPerms, dynamicRoutes);
          const newRoutes = accessedRoutes.concat(accessedRoutes2);
          setRoutes(newRoutes);
          resolve(newRoutes);
        })
        .catch((error) => {
          reject(error);
        });
    });
  }

  /**
   * 获取与激活的顶部菜单项相关的混合模式左侧菜单集合
   */
  const mixLeftMenus = ref<RouteRecordRaw[]>([]);
  function setMixLeftMenus(topMenuPath: string) {
    const matchedItem = routes.value.find((item) => item.path === topMenuPath);
    if (matchedItem && matchedItem.children) {
      mixLeftMenus.value = matchedItem.children;
    }
  }
  return {
    routes,
    setRoutes,
    generateRoutes,
    mixLeftMenus,
    setMixLeftMenus
  };
});

// 非setup
export function usePermissionStoreHook() {
  return usePermissionStore(store);
}
